#include "UdpSocket.hpp"
#include "hiScopeGuard.h"
#include <string.h>
#include <uv.h>
#include "DepLibUV.hpp"
#include <cstring>
#include<stdio.h>
#include "common/HiCommonLog.hpp"

const size_t UdpSocket::READ_BUFFER_SIZE = 65536;

void UdpSocket::onClose(uv_handle_t *handle) {
	HI_FUNC_DEBUG();
	if (nullptr == handle || nullptr == handle->data) {
		HI_DEBUG("UdpSocket onClose handle is nullptr\n");
		return;
	}
	
	UdpSocket * udp = static_cast<UdpSocket *>(handle->data);
	if (nullptr == udp) {
		return;
	}
	udp->OnUvClosed();
	delete udp; 
}

void UdpSocket::OnUvClosed() {
	HI_FUNC_DEBUG();
	if (nullptr == this->uvHandle) {
		this->onCloseCallBack();
		return;
	}
	delete this->uvHandle;
	this->uvHandle = nullptr;	
	this->onCloseCallBack();	
}

/* Instance methods. */
UdpSocket::UdpSocket() {
	DepLibUV::ClassInit();
	this->receiveDataCallBack = default_OnReceive;
	this->onCloseCallBack = default_OnClose;
	this->onSendFailed = default_OnSendFailed;
	
	this->readBuffer = new uint8_t[UdpSocket::READ_BUFFER_SIZE];
	::memset(this->readBuffer, 0, UdpSocket::READ_BUFFER_SIZE);
}

UdpSocket::~UdpSocket() {
	HI_FUNC_DEBUG();
	if (this->readBuffer != nullptr) {
		delete[] this->readBuffer;
		this->readBuffer = nullptr;
		HI_DEBUG("UdpSocket::~UdpSocket delete readBuffer\n");
	}
	
	if (this->uvHandle != nullptr) {
		delete this->uvHandle;
		this->uvHandle = nullptr;
		HI_DEBUG("UdpSocket::~UdpSocket finsh\n");
	} else {
		HI_DEBUG("UdpSocket::~UdpSocket this->uvHandle is nullptr\n");
	}
}
void UdpSocket::Destroy() {
	HI_FUNC_DEBUG();
	if (this->isClosing)
		return;

	this->isClosing = true;

	// Don't read more.
	int err = uv_udp_recv_stop(this->uvHandle);
	if (err != 0) {
		// MS_ABORT("uv_udp_recv_stop() failed: %s", uv_strerror(err));
		HI_DEBUG("uv_udp_recv_stop failed\n");
		return;
	} else {
		HI_DEBUG("uv_udp_recv_stop success\n");
	}

	uv_close(reinterpret_cast<uv_handle_t *>(this->uvHandle),
		   static_cast<uv_close_cb>(UdpSocket::onClose)
	);
	HI_DEBUG("UdpSocket::Destroy uv_close\n");
}

const struct sockaddr *UdpSocket::GetLocalAddress() const {
	return reinterpret_cast<const struct sockaddr *>(&this->localAddr);
}

std::string UdpSocket::GetLocalIP() {
	return this->localIP;
}

uint16_t UdpSocket::GetLocalPort() const {
	return this->localPort;
}

size_t UdpSocket::GetRecvBytes() const {
	return this->recvBytes;
}
size_t UdpSocket::GetSentBytes() const {
	return this->sentBytes;
}